package cz.proks.easyhelpdesk.gwt.activity;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

import cz.proks.easyhelpdesk.api.model.HelpdeskMember;
import cz.proks.easyhelpdesk.api.model.Thread;
import cz.proks.easyhelpdesk.api.model.ThreadMember;
import cz.proks.easyhelpdesk.api.model.Ticket;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.api.model.base.Id;
import cz.proks.easyhelpdesk.gwt.ClientFactory;
import cz.proks.easyhelpdesk.gwt.Globals;
import cz.proks.easyhelpdesk.gwt.activity.base.RestrictedHelpdeskActivity;
import cz.proks.easyhelpdesk.gwt.place.ThreadPlace;
import cz.proks.easyhelpdesk.gwt.restapi.RestIdCallback;
import cz.proks.easyhelpdesk.gwt.restapi.ThreadRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.TicketRestApi;
import cz.proks.easyhelpdesk.gwt.ui.ThreadView;
import cz.proks.easyhelpdesk.gwt.ui.base.RestrictedHelpdeskView;
import cz.proks.easyhelpdesk.gwt.utils.RestUtils;

public class ThreadActivity extends RestrictedHelpdeskActivity<ThreadPlace> implements ThreadView.Presenter {
    private ThreadView view;
    private Thread thread;
    
    public ThreadActivity(ThreadPlace place, ClientFactory clientFactory, PlaceHistoryMapper placeMapper) {
        super(place, clientFactory, placeMapper);        
        this.view = clientFactory.getThreadView();         
    }

    @Override
    protected RestrictedHelpdeskView getView() {
        return view;
    }

    @Override
    protected void onPermission(AcceptsOneWidget panel, EventBus eventBus) {
        this.thread = getThread(getPlace().getThreadId());
        
        view.setPresenter(this);        
        view.setUsers(getUsers());
        view.setCategories(Globals.getCategoryMapFor(Globals.getCurrentHelpdesk()));
        view.setTickets(getThreadTickets(thread));
        
        panel.setWidget(view);
    }    

    @Override
    public void saveReplyTicket(final Ticket ticket) {        
        completeTicket(ticket);
        
        if (!isTicketOkBeforeSave(ticket))
            return;        
        
        // save ticket
        new TicketRestApi().create(ticket, new RestIdCallback() {
            
            @Override
            public void onIdSuccess(Id id) {
                ticket.setId(id.getId());
               
                // add ticket to thread
                new ThreadRestApi().addTicket(thread.getId(), ticket.getId(), new RestUtils.Callback() {
                    
                    @Override
                    public void onSuccess(JSONValue val) {
                        thread.getTickets().add(ticket);
                        view.setUsers(getUsers());
                        view.setTickets(getThreadTickets(thread));
                    }
                });                
            }
        });     
    } 
    
    private Ticket completeTicket(Ticket ticket) {        
        ticket.setCreated(new Date());        
        ticket.setOwnerId(Globals.getCurrentUser().getId());                
        ticket.setThreadId(getPlace().getThreadId());
        
        return ticket;
    }
    
    private boolean isTicketOkBeforeSave(Ticket ticket) {
        if (ticket.getSubject() == null || ticket.getSubject().isEmpty()) {
            Window.alert(getClientFactory().getHelpdeskMessages().errorTicketSubjectEmpty());
            return false;
        }

        else if (ticket.getCategoryId() == null) {
            Window.alert(getClientFactory().getHelpdeskMessages().errorTicketCategoryEmpty());
            return false;
        }

        return true;
    }
    
    private Thread getThread(Long threadId) {
        HelpdeskMember helpdeskMember = Globals.getCurrentHelpdeskMember();
        Map<Long, ThreadMember> threadMembers = Globals.getThreadMemberMapFor(helpdeskMember);
        
        for (ThreadMember threadMember : threadMembers.values())
            if (threadMember.getThreadId().equals(threadId))
                return Globals.getThreadFor(threadMember); 
        
        return null; 
    }
        
    private Map<Long, User> getUsers() {
        Map<Long, User> users = new LinkedHashMap<Long, User>();        
        Collection<Ticket> tickets = thread.getTickets();        
        
        for (Ticket ticket : tickets) {
            HelpdeskMember helpdeskMember = Globals.getHelpdeskMemberFor(Globals.getCurrentHelpdesk(), ticket.getOwnerId());
            User user = Globals.getUserFor(helpdeskMember); 
            users.put(user.getId(), user);
        }
        
        return users;
    }
    
    private Collection<Ticket> getThreadTickets(Thread thread) {
        List<Ticket> tickets = new LinkedList<Ticket>();
        
        if (thread.getTickets() != null) {
            tickets.addAll(thread.getTickets());
            
            Collections.sort(tickets, new Comparator<Ticket>() {
                @Override
                public int compare(Ticket o1, Ticket o2) {
                    return o1.getCreated().compareTo(o2.getCreated());
                }
            });
        }
        
        return tickets;
    }
}
